// Copyright Epic Games, Inc. All Rights Reserved.

#include "Input/AimAssistTargetManagerComponent.h" // 包含瞄准辅助目标管理器组件头文件
#include "CommonInputTypeEnum.h" // 通用输入类型枚举
#include "Engine/OverlapResult.h" // 重叠结果
#include "Engine/World.h" // 世界
#include "GameFramework/InputSettings.h" // 输入设置
#include "GameFramework/Character.h" // 角色
#include "GameFramework/InputSettings.h" // 输入设置
#include "Components/CapsuleComponent.h" // 胶囊体组件
#include "Components/SkeletalMeshComponent.h" // 骨骼网格组件
#include "Character/LyraHealthComponent.h" // Lyra生命值组件
#include "Input/AimAssistInputModifier.h" // 瞄准辅助输入修改器
#include "Player/LyraPlayerState.h" // Lyra玩家状态
#include "Character/LyraHealthComponent.h" // Lyra生命值组件
#include "Input/IAimAssistTargetInterface.h" // 瞄准辅助目标接口
#include "ShooterCoreRuntimeSettings.h" // 射击核心运行时设置

#include UE_INLINE_GENERATED_CPP_BY_NAME(AimAssistTargetManagerComponent) // 包含内联生成的cpp文件

namespace LyraConsoleVariables // Lyra控制台变量命名空间
{
    static bool bDrawDebugViewfinder = false; // 静态布尔变量：绘制调试取景器
    static FAutoConsoleVariableRef CVarDrawDebugViewfinder( // 自动控制台变量引用
        TEXT("lyra.Weapon.AimAssist.DrawDebugViewfinder"), // 控制台变量名称
        bDrawDebugViewfinder, // 变量引用
        TEXT("Should we draw a debug box for the aim assist target viewfinder?"), // 帮助文本
        ECVF_Cheat); // 控制台变量标志（作弊）
}

const FLyraAimAssistTarget* FindTarget(const TArray<FLyraAimAssistTarget>& Targets, const UShapeComponent* TargetComponent) // 查找目标
{
    const FLyraAimAssistTarget* FoundTarget = Targets.FindByPredicate( // 找到的目标：通过谓词查找
    [&TargetComponent](const FLyraAimAssistTarget& Target) // lambda表达式，参数为目标
    {
        return (Target.TargetShapeComponent == TargetComponent); // 返回目标形状组件是否等于目标组件
    });

    return FoundTarget; // 返回找到的目标
}

static bool GatherTargetInfo(const AActor* Actor, const UShapeComponent* ShapeComponent, FTransform& OutTransform, FCollisionShape& OutShape, FVector& OutShapeOrigin) // 收集目标信息
{
    check(Actor); // 检查actor
    check(ShapeComponent); // 检查形状组件

    const FCollisionShape TargetShape = ShapeComponent->GetCollisionShape(); // 目标形状：获取碰撞形状
    const bool bIsValidShape = (TargetShape.IsBox() || TargetShape.IsSphere() || TargetShape.IsCapsule()); // 是否有效形状

    if (!bIsValidShape || TargetShape.IsNearlyZero()) // 如果不是有效形状或形状接近零
    {
        return false; // 返回false
    }

    FTransform TargetTransform; // 目标变换
    FVector TargetShapeOrigin(ForceInitToZero); // 目标形状原点强制初始化为零

    if (const ACharacter* TargetCharacter = Cast<ACharacter>(Actor)) // 如果actor是角色
    {
        if (ShapeComponent == TargetCharacter->GetCapsuleComponent()) // 如果形状组件是角色的胶囊体组件
        {
            // 远程玩家的角色胶囊体不会平滑移动。使用网格位置，因为它是平滑的。
            const USkeletalMeshComponent* TargetMesh = TargetCharacter->GetMesh(); // 目标网格：获取网格
            check(TargetMesh); // 检查目标网格

            TargetTransform = TargetMesh->GetComponentTransform(); // 目标变换：网格组件变换
            TargetShapeOrigin = -TargetCharacter->GetBaseTranslationOffset(); // 目标形状原点：负基础平移偏移
        }
        else // 否则
        {
            TargetTransform = ShapeComponent->GetComponentTransform(); // 目标变换：形状组件变换
        }
    }
    else // 否则
    {
        TargetTransform = ShapeComponent->GetComponentTransform(); // 目标变换：形状组件变换
    }

    OutTransform = TargetTransform; // 输出变换
    OutShape = TargetShape; // 输出形状
    OutShapeOrigin = TargetShapeOrigin; // 输出形状原点

    return true; // 返回true
}


void UAimAssistTargetManagerComponent::GetVisibleTargets(const FAimAssistFilter& Filter, const FAimAssistSettings& Settings, const FAimAssistOwnerViewData& OwnerData, const TArray<FLyraAimAssistTarget>& OldTargets, OUT TArray<FLyraAimAssistTarget>& OutNewTargets) // 获取可见目标
{
    TRACE_CPUPROFILER_EVENT_SCOPE(UAimAssistTargetManagerComponent::GetVisibleTargets); // CPU性能分析器事件范围
    OutNewTargets.Reset(); // 重置新目标数组
    const APlayerController* PC = OwnerData.PlayerController; // 玩家控制器
    
    if (!PC) // 如果玩家控制器为空
    {
        UE_LOG(LogAimAssist, Error, TEXT("Invalid player controller passed to GetVisibleTargets!")); // 日志：传递给GetVisibleTargets的玩家控制器无效
        return; // 返回
    }

    const APawn* OwnerPawn = PC->GetPawn(); // 拥有者pawn

    if (!OwnerPawn) // 如果拥有者pawn为空
    {
        UE_LOG(LogAimAssist, Error, TEXT("Could not find a valid pawn for aim assist!")); // 日志：无法找到有效的pawn用于瞄准辅助
        return;    // 返回
    }
    
    const FVector ViewLocation = OwnerData.ViewTransform.GetTranslation(); // 视图位置：视图变换的平移
    const FVector ViewForward = OwnerData.ViewTransform.GetUnitAxis(EAxis::X); // 视图前向：视图变换的X轴单位向量

    const float FOVScale = GetFOVScale(PC, ECommonInputType::Gamepad); // 视野缩放：获取视野缩放
    const float InvFieldOfViewScale = (FOVScale > 0.0f) ? (1.0f / FOVScale) : 1.0f; // 逆视野缩放：如果视野缩放大于0则为倒数，否则为1
    const float TargetRange = (Settings.TargetRange.GetValue() * InvFieldOfViewScale); // 目标范围：设置值乘以逆视野缩放

    // 使用视野缩放准星投影。这保持准星大小不变，无论视野如何。
    const float ReticleDepth = (Settings.ReticleDepth * InvFieldOfViewScale); // 准星深度：设置值乘以逆视野缩放

    // 计算此准星在屏幕空间中的边界
    const FBox2D AssistInnerReticleBounds = OwnerData.ProjectReticleToScreen(Settings.AssistInnerReticleWidth.GetValue(), Settings.AssistInnerReticleHeight.GetValue(), ReticleDepth); // 辅助内准星边界：投影准星到屏幕
    const FBox2D AssistOuterReticleBounds = OwnerData.ProjectReticleToScreen(Settings.AssistOuterReticleWidth.GetValue(), Settings.AssistOuterReticleHeight.GetValue(), ReticleDepth); // 辅助外准星边界：投影准星到屏幕
    const FBox2D TargetingReticleBounds = OwnerData.ProjectReticleToScreen(Settings.TargetingReticleWidth.GetValue(), Settings.TargetingReticleHeight.GetValue(), ReticleDepth); // 瞄准准星边界：投影准星到屏幕

    static TArray<FOverlapResult> OverlapResults; // 静态重叠结果数组
    // 在瞄准辅助通道上执行世界追踪以获取任何可见目标
    {
        UWorld* World = GetWorld(); // 世界
        
        OverlapResults.Reset(); // 重置重叠结果

        const FVector PawnLocation = OwnerPawn->GetActorLocation(); // pawn位置：actor位置
        ECollisionChannel AimAssistChannel = GetAimAssistChannel(); // 瞄准辅助通道：获取瞄准辅助通道
        FCollisionQueryParams Params(SCENE_QUERY_STAT(AimAssist_QueryTargetsInRange), true); // 碰撞查询参数：场景查询统计，跟踪响应
        Params.AddIgnoredActor(OwnerPawn); // 添加忽略actor

        // 需要乘以0.5，因为MakeBox接受半范围
        FCollisionShape BoxShape = FCollisionShape::MakeBox(FVector3f(ReticleDepth * 0.5f, Settings.AssistOuterReticleWidth.GetValue() * 0.5f, Settings.AssistOuterReticleHeight.GetValue() * 0.5f));                        // 盒子形状：创建盒子
        World->OverlapMultiByChannel(OUT OverlapResults, PawnLocation, OwnerData.PlayerTransform.GetRotation(), AimAssistChannel, BoxShape, Params); // 重叠多重按通道

#if ENABLE_DRAW_DEBUG && !UE_BUILD_SHIPPING // 如果启用绘制调试且不是发布版本
        if(LyraConsoleVariables::bDrawDebugViewfinder) // 如果绘制调试取景器
        {
            DrawDebugBox(World, PawnLocation, BoxShape.GetBox(), OwnerData.PlayerTransform.GetRotation(), FColor::Red);    // 绘制调试盒子
        }
#endif
    }

    // 从任何实现IAimAssistTarget接口的可见命中结果收集目标选项
    TArray<FAimAssistTargetOptions> NewTargetData; // 新目标数据数组
    {
        for (const FOverlapResult& Overlap : OverlapResults) // 遍历重叠结果
        {
            TScriptInterface<IAimAssistTaget> TargetActor(Overlap.GetActor()); // 目标actor：脚本接口
            if (TargetActor) // 如果目标actor存在
            {
                FAimAssistTargetOptions TargetData; // 目标数据
                TargetActor->GatherTargetOptions(TargetData); // 收集目标选项
                NewTargetData.Add(TargetData); // 添加目标数据
            }
            
            TScriptInterface<IAimAssistTaget> TargetComponent(Overlap.GetComponent()); // 目标组件：脚本接口
            if (TargetComponent) // 如果目标组件存在
            {
                FAimAssistTargetOptions TargetData; // 目标数据
                TargetComponent->GatherTargetOptions(TargetData); // 收集目标选项
                NewTargetData.Add(TargetData); // 添加目标数据
            }            
        }
    }
    
    // 收集玩家前方的目标
    {
        const FVector PawnLocation = OwnerPawn->GetActorLocation();        // pawn位置：actor位置
        
        for (FAimAssistTargetOptions& AimAssistTarget : NewTargetData) // 遍历新目标数据
        {
            if (!DoesTargetPassFilter(OwnerData, Filter, AimAssistTarget, TargetRange)) // 如果目标未通过过滤器
            {
                continue; // 继续
            }
            
            AActor* OwningActor = AimAssistTarget.TargetShapeComponent->GetOwner(); // 所属actor：目标形状组件的拥有者

            FTransform TargetTransform; // 目标变换
            FCollisionShape TargetShape; // 目标形状
            FVector TargetShapeOrigin; // 目标形状原点

            if (!GatherTargetInfo(OwningActor, AimAssistTarget.TargetShapeComponent.Get(), TargetTransform, TargetShape, TargetShapeOrigin)) // 如果收集目标信息失败
            {
                continue; // 继续
            }
            
            const FVector TargetViewLocation = TargetTransform.TransformPositionNoScale(TargetShapeOrigin); // 目标视图位置：目标变换转换位置
            const FVector TargetViewVector = (TargetViewLocation - ViewLocation); // 目标视图向量

            FVector TargetViewDirection; // 目标视图方向
            float TargetViewDistance; // 目标视图距离
            TargetViewVector.ToDirectionAndLength(TargetViewDirection, TargetViewDistance); // 转换为方向和长度
            const float TargetViewDot = FVector::DotProduct(TargetViewDirection, ViewForward); // 目标视图点积
            if (TargetViewDot <= 0.0f) // 如果目标视图点积小于等于0
            {
                continue; // 继续
            }
            
            const FLyraAimAssistTarget* OldTarget = FindTarget(OldTargets, AimAssistTarget.TargetShapeComponent.Get()); // 旧目标：查找目标

            // 计算此目标的屏幕边界
            FBox2D TargetScreenBounds(ForceInitToZero); // 目标屏幕边界强制初始化为零
            const bool bUpdateTargetProjections = true; // 是否更新目标投影
            if (bUpdateTargetProjections) // 如果更新目标投影
            {
                TargetScreenBounds = OwnerData.ProjectShapeToScreen(TargetShape, TargetShapeOrigin, TargetTransform); // 目标屏幕边界：投影形状到屏幕
            }
            else // 否则
            {
                // 未更新目标投影，因此如果目标存在，则使用上一帧的值。
                if (OldTarget) // 如果旧目标存在
                {
                    TargetScreenBounds = OldTarget->ScreenBounds; // 目标屏幕边界设为旧目标的屏幕边界
                }
            }

            if (!TargetScreenBounds.bIsValid) // 如果目标屏幕边界无效
            {
                continue; // 继续
            }

            if (!TargetingReticleBounds.Intersect(TargetScreenBounds)) // 如果瞄准准星边界不与目标屏幕边界相交
            {
                continue; // 继续
            }

            FLyraAimAssistTarget NewTarget; // 新目标

            NewTarget.TargetShapeComponent = AimAssistTarget.TargetShapeComponent; // 目标形状组件
            NewTarget.Location = TargetTransform.GetTranslation(); // 位置：目标变换的平移
            NewTarget.ScreenBounds = TargetScreenBounds; // 屏幕边界
            NewTarget.ViewDistance = TargetViewDistance; // 视图距离
            NewTarget.bUnderAssistInnerReticle = AssistInnerReticleBounds.Intersect(TargetScreenBounds); // 是否在辅助内准星下：边界相交
            NewTarget.bUnderAssistOuterReticle = AssistOuterReticleBounds.Intersect(TargetScreenBounds); // 是否在辅助外准星下：边界相交
            
            // 从上一帧传输目标数据。
            if (OldTarget) // 如果旧目标存在
            {
                NewTarget.DeltaMovement = (NewTarget.Location - OldTarget->Location); // 增量移动
                NewTarget.AssistTime = OldTarget->AssistTime; // 辅助时间
                NewTarget.AssistWeight = OldTarget->AssistWeight; // 辅助权重
                NewTarget.VisibilityTraceHandle = OldTarget->VisibilityTraceHandle; // 可见性追踪句柄
            }

            // 基于先前的权重、与目标的距离以及与准星的距离计算用于排序的分数。
            const float AssistWeightScore = (NewTarget.AssistWeight * Settings.TargetScore_AssistWeight); // 辅助权重分数
            const float ViewDotScore = ((TargetViewDot * Settings.TargetScore_ViewDot) - Settings.TargetScore_ViewDotOffset); // 视图点积分
            const float ViewDistanceScore = ((1.0f - (TargetViewDistance / TargetRange)) * Settings.TargetScore_ViewDistance); // 视图距离分数

            NewTarget.SortScore = (AssistWeightScore + ViewDotScore + ViewDistanceScore); // 排序分数

            OutNewTargets.Add(NewTarget); // 添加新目标
        }
    }

    // 按分数对目标排序，以便如果目标太多，我们可以限制执行的可见性追踪数量。
    if (OutNewTargets.Num() > Settings.MaxNumberOfTargets) // 如果新目标数量大于最大目标数量
    {
        OutNewTargets.Sort([](const FLyraAimAssistTarget& TargetA, const FLyraAimAssistTarget& TargetB) // 排序
        {
            return (TargetA.SortScore > TargetB.SortScore); // 返回排序分数比较
        });
        
        OutNewTargets.SetNum(Settings.MaxNumberOfTargets, EAllowShrinking::No); // 设置数量为最大目标数量，不允许缩小
    }

    // 对目标执行可见性追踪
    {
        for (FLyraAimAssistTarget& Target : OutNewTargets) // 遍历新目标
        {
            DetermineTargetVisibility(Target, Settings, Filter, OwnerData); // 确定目标可见性
        }
    }
}

bool UAimAssistTargetManagerComponent::DoesTargetPassFilter(const FAimAssistOwnerViewData& OwnerData, const FAimAssistFilter& Filter, const FAimAssistTargetOptions& Target, const float AcceptableRange) const // 目标是否通过过滤器
{
    const APawn* OwnerPawn = OwnerData.PlayerController ? OwnerData.PlayerController->GetPawn() : nullptr; // 拥有者pawn：如果玩家控制器存在则获取pawn，否则为空
    
    if (!Target.bIsActive || !OwnerPawn || !Target.TargetShapeComponent.IsValid()) // 如果目标不活动或拥有者pawn为空或目标形状组件无效
    {
        return false; // 返回false
    }
    
    const AActor* TargetOwningActor = Target.TargetShapeComponent->GetOwner(); // 目标所属actor：目标形状组件的拥有者
    check(TargetOwningActor); // 检查目标所属actor
    if (TargetOwningActor == OwnerPawn || TargetOwningActor == OwnerPawn->GetInstigator()) // 如果目标所属actor等于拥有者pawn或拥有者pawn的发起者
    {
        return false; // 返回false
    }
    
    const FVector PawnLocation = OwnerPawn->GetActorLocation(); // pawn位置：actor位置
    
    // 对给定actor执行距离检查
    const FVector TargetVector = TargetOwningActor->GetActorLocation() - PawnLocation; // 目标向量
    const float TargetViewDistanceCheck = FVector::DotProduct(OwnerData.ViewForward, TargetVector); // 目标视图距离检查：点积

    if ((TargetViewDistanceCheck < 0.0f) || (TargetViewDistanceCheck > AcceptableRange)) // 如果目标视图距离检查小于0或大于可接受范围
    {
        return false; // 返回false
    }
    
    if (const ACharacter* TargetCharacter = Cast<ACharacter>(TargetOwningActor)) // 如果目标所属actor是角色
    {
        // 如果给定目标与拥有者在同一队伍，则从搜索中排除它    
        if (!Filter.bIncludeSameFriendlyTargets) // 如果不包含同队目标
        {
            if (const ALyraPlayerState* PS = TargetCharacter->GetPlayerState<ALyraPlayerState>()) // 如果获取到Lyra玩家状态
            {
                if (PS->GetTeamId() == OwnerData.TeamID) // 如果队伍ID相等
                {
                    return false; // 返回false
                }
            }
        }

        // 排除死亡或濒死的角色
        if (Filter.bExcludeDeadOrDying) // 如果排除死亡或濒死目标
        {
            if (const ULyraHealthComponent* HealthComponent = ULyraHealthComponent::FindHealthComponent(TargetCharacter)) // 如果找到生命值组件
            {
                if (HealthComponent->IsDeadOrDying()) // 如果死亡或濒死
                {
                    return false; // 返回false
                }
            }    
        }
    }

    // 如果此目标具有过滤器要排除的任何标签，则忽略它
    if (Target.AssociatedTags.HasAny(Filter.ExclusionGameplayTags)) // 如果关联标签包含任何排除的游戏标签
    {
        return false; // 返回false
    }

    if (Filter.ExcludedClasses.Contains(TargetOwningActor->GetClass())) // 如果排除的类包含目标所属actor的类
    {
        return false; // 返回false
    }

    return true; // 返回true
}

float UAimAssistTargetManagerComponent::GetFOVScale(const APlayerController* PC, ECommonInputType InputType) // 获取视野缩放
{
    float FovScale = 1.0f; // 视野缩放初始为1
    const UInputSettings* DefaultInputSettings = GetDefault<UInputSettings>(); // 默认输入设置
    check(DefaultInputSettings && PC); // 检查默认输入设置和玩家控制器

    if (PC->PlayerCameraManager && DefaultInputSettings->bEnableFOVScaling) // 如果玩家摄像机管理器存在且启用视野缩放
    {
        const float FOVAngle = PC->PlayerCameraManager->GetFOVAngle(); // 视野角度
        switch (InputType) // 根据输入类型切换
        {
        case ECommonInputType::Gamepad: // 游戏手柄
        case ECommonInputType::Touch: // 触摸
        {
            static const float PlayerInput_BaseFOV = 80.0f; // 静态常量：玩家输入基础视野
            // 这是基于视野变化进行缩放的正确方式。
            // 理想情况下鼠标也会使用此方式，但现在更改会导致现有玩家的灵敏度发生变化。
            const float BaseHalfFOV = PlayerInput_BaseFOV * 0.5f; // 基础半视野
            const float HalfFOV = FOVAngle * 0.5f; // 半视野
            const float BaseTanHalfFOV = FMath::Tan(FMath::DegreesToRadians(BaseHalfFOV)); // 基础半视野正切
            const float TanHalfFOV = FMath::Tan(FMath::DegreesToRadians(HalfFOV)); // 半视野正切

            check(BaseTanHalfFOV > 0.0f); // 检查基础半视野正切大于0
            FovScale = (TanHalfFOV / BaseTanHalfFOV); // 视野缩放：半视野正切除以基础半视野正切
            break; // 跳出
        }
        case ECommonInputType::MouseAndKeyboard: // 鼠标和键盘
            FovScale = (DefaultInputSettings->FOVScale * FOVAngle); // 视野缩放：默认输入设置的视野缩放乘以视野角度
            break; // 跳出
        default: // 默认
            ensure(false); // 确保false
            break; // 跳出
        }
    }
    return FovScale; // 返回视野缩放
}

void UAimAssistTargetManagerComponent::DetermineTargetVisibility(FLyraAimAssistTarget& Target, const FAimAssistSettings& Settings, const FAimAssistFilter& Filter, const FAimAssistOwnerViewData& OwnerData) // 确定目标可见性
{
    UWorld* World = GetWorld(); // 世界
    check(World); // 检查世界

    const AActor* Actor = Target.TargetShapeComponent->GetOwner(); // actor：目标形状组件的拥有者
    if (!Actor) // 如果actor为空
    {
        ensure(false); // 确保false
        return; // 返回
    }

    FVector TargetEyeLocation; // 目标眼睛位置
    FRotator TargetEyeRotation; // 目标眼睛旋转
    Actor->GetActorEyesViewPoint(TargetEyeLocation, TargetEyeRotation); // 获取actor眼睛视点
    
    FCollisionQueryParams QueryParams(SCENE_QUERY_STAT(AimAssist_DetermineTargetVisibility), true); // 碰撞查询参数：场景查询统计，跟踪响应
    InitTargetSelectionCollisionParams(QueryParams, *Actor, Filter); // 初始化目标选择碰撞参数
    QueryParams.AddIgnoredActor(Actor); // 添加忽略actor

    const UShooterCoreRuntimeSettings* ShooterSettings = GetDefault<UShooterCoreRuntimeSettings>(); // 射击核心运行时设置
    const ECollisionChannel AimAssistChannel = ShooterSettings->GetAimAssistCollisionChannel(); // 瞄准辅助通道：获取瞄准辅助碰撞通道
        
    FCollisionResponseParams ResponseParams; // 碰撞响应参数
    ResponseParams.CollisionResponse.SetResponse(ECC_Pawn, ECR_Ignore);    // 碰撞响应设置：pawn通道忽略
    ResponseParams.CollisionResponse.SetResponse(AimAssistChannel, ECR_Ignore); // 碰撞响应设置：瞄准辅助通道忽略

    if (Target.bIsVisible && Settings.bEnableAsyncVisibilityTrace) // 如果目标可见且启用异步可见性追踪
    {
        // 查询先前的异步追踪结果。
        if (Target.VisibilityTraceHandle.IsValid()) // 如果可见性追踪句柄有效
        {
            FTraceDatum TraceDatum; // 追踪数据
            if (World->QueryTraceData(Target.VisibilityTraceHandle, TraceDatum)) // 如果查询追踪数据成功
            {
                Target.bIsVisible = (FHitResult::GetFirstBlockingHit(TraceDatum.OutHits) == nullptr); // 目标可见性：第一个阻挡命中是否为空
            }
            else // 否则
            {
                UE_LOG(LogAimAssist, Warning, TEXT("UAimAssistTargetManagerComponent::DetermineTargetVisibility() - Failed to find async visibility trace data!")); // 日志：找不到异步可见性追踪数据
                Target.bIsVisible = false; // 目标不可见
            }

            // 使异步追踪句柄无效。
            Target.VisibilityTraceHandle = FTraceHandle(); // 可见性追踪句柄置空
        }

        // 仅当目标仍然可见时才为下一帧启动新的异步追踪。
        if (Target.bIsVisible) // 如果目标可见
        {
            Target.VisibilityTraceHandle = World->AsyncLineTraceByChannel(EAsyncTraceType::Test, OwnerData.ViewTransform.GetTranslation(), TargetEyeLocation, ECC_Visibility, QueryParams, ResponseParams); // 异步线追踪按通道
        }
    }
    else // 否则
    {
        Target.bIsVisible = !World->LineTraceTestByChannel(OwnerData.ViewTransform.GetTranslation(), TargetEyeLocation, ECC_Visibility, QueryParams, ResponseParams); // 目标可见性：线追踪测试按通道取反

        // 使异步追踪句柄无效。
        Target.VisibilityTraceHandle = FTraceHandle();        // 可见性追踪句柄置空
    }
}

void UAimAssistTargetManagerComponent::InitTargetSelectionCollisionParams(FCollisionQueryParams& OutParams, const AActor& RequestedBy, const FAimAssistFilter& Filter) const // 初始化目标选择碰撞参数
{
    // 排除请求者
    if (Filter.bExcludeRequester) // 如果排除请求者
    {
        OutParams.AddIgnoredActor(&RequestedBy); // 添加忽略actor
    }

    // 排除附加到请求者的所有actor
    if (Filter.bExcludeAllAttachedToRequester) // 如果排除附加到请求者的所有actor
    {
        TArray<AActor*> ActorsAttachedToRequester; // 附加到请求者的actor数组
        RequestedBy.GetAttachedActors(ActorsAttachedToRequester); // 获取附加的actor

        OutParams.AddIgnoredActors(ActorsAttachedToRequester); // 添加忽略actor
    }

    if (Filter.bExcludeInstigator) // 如果排除发起者
    {
        OutParams.AddIgnoredActor(RequestedBy.GetInstigator()); // 添加忽略actor
    }

    // 排除附加到发起者的所有actor
    if (Filter.bExcludeAllAttachedToInstigator && RequestedBy.GetInstigator()) // 如果排除附加到发起者的所有actor且发起者存在
    {
        TArray<AActor*> ActorsAttachedToInstigator; // 附加到发起者的actor数组
        RequestedBy.GetInstigator()->GetAttachedActors(ActorsAttachedToInstigator); // 获取附加的actor

        OutParams.AddIgnoredActors(ActorsAttachedToInstigator); // 添加忽略actor
    }

    OutParams.bTraceComplex = Filter.bTraceComplexCollision; // 是否追踪复杂碰撞
}

ECollisionChannel UAimAssistTargetManagerComponent::GetAimAssistChannel() const // 获取瞄准辅助通道
{
    const UShooterCoreRuntimeSettings* ShooterSettings = GetDefault<UShooterCoreRuntimeSettings>(); // 射击核心运行时设置
    const ECollisionChannel AimAssistChannel = ShooterSettings->GetAimAssistCollisionChannel(); // 瞄准辅助通道：获取瞄准辅助碰撞通道

    ensureMsgf(AimAssistChannel != ECollisionChannel::ECC_MAX, TEXT("The aim assist collision channel has not been set! Do this in the ShooterCoreRuntime plugin settings")); // 确保消息：瞄准辅助碰撞通道未设置
    
    return AimAssistChannel; // 返回瞄准辅助通道
}